/* Includes ------------------------------------------------------------------*/
#include "SystemTick.h"
#include "Led.h"
#include "RF.h"
#include "Button.h"

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define BUTTON_DEBOUNCE         100                             // 100ms
#define TIME_TO_LEARN           ( 2000 / BUTTON_DEBOUNCE )      // 2s
#define TIMEOUT_LEARN_BUTTON    5000                            // 5s

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
U8 s_PrescaleCnt = 0;
U8 s_SwStatus;
U8 s_SwChange;

U8 s_LearnPrescaleCnt = 0;

eButtonMode s_ButtonMode;
U16 s_TimeoutLearnButtonCnt = 0;

/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/* Public functions ----------------------------------------------------------*/

U8 Button_GetStatus(void)
{
    U8 status = 0;
    if( RESET == GPIO_ReadInputPin(BUTTON1_PORT, BUTTON1_PINS) ) status |= BUTTON1_ACTIVE;
    if( RESET == GPIO_ReadInputPin(BUTTON2_PORT, BUTTON2_PINS) ) status |= BUTTON2_ACTIVE;
    if( RESET == GPIO_ReadInputPin(BUTTON3_PORT, BUTTON3_PINS) ) status |= BUTTON3_ACTIVE;
    if( RESET == GPIO_ReadInputPin(BUTTON4_PORT, BUTTON4_PINS) ) status |= BUTTON4_ACTIVE;
    if( RESET == GPIO_ReadInputPin(BUTTON5_PORT, BUTTON5_PINS) ) status |= BUTTON5_ACTIVE;
    if( RESET == GPIO_ReadInputPin(BUTTON6_PORT, BUTTON6_PINS) ) status |= BUTTON6_ACTIVE;

    return( status );
}

void Button_TimerInterrupt(void)
{
    U8 newStatus;
    if( 0xFFFF > s_TimeoutLearnButtonCnt ) ++s_TimeoutLearnButtonCnt;
    if (BUTTON_DEBOUNCE <= ++s_PrescaleCnt)
    {
        s_PrescaleCnt = 0;

        if ( s_LearnPrescaleCnt < 0xFF ) ++s_LearnPrescaleCnt;

        newStatus = Button_GetStatus();
        s_SwChange = newStatus ^ s_SwStatus;
        s_SwStatus = newStatus;
    }
}


void Button_Init(void)
{
    // Initialize I/Os in Output Mode
    GPIO_Init(BUTTON1_PORT, BUTTON1_PINS, GPIO_MODE_IN_PU_NO_IT);
    GPIO_Init(BUTTON2_PORT, BUTTON2_PINS, GPIO_MODE_IN_PU_NO_IT);
    GPIO_Init(BUTTON3_PORT, BUTTON3_PINS, GPIO_MODE_IN_PU_NO_IT);
    GPIO_Init(BUTTON4_PORT, BUTTON4_PINS, GPIO_MODE_IN_PU_NO_IT);
    GPIO_Init(BUTTON5_PORT, BUTTON5_PINS, GPIO_MODE_IN_PU_NO_IT);
    GPIO_Init(BUTTON6_PORT, BUTTON6_PINS, GPIO_MODE_IN_PU_NO_IT);

    SysTick_Registration(&Button_TimerInterrupt);
    s_SwStatus = Button_GetStatus();
    s_SwChange = 0;
    s_ButtonMode = NORMAL_BUTTON;
}


eButtonMode Button_GetMode()
{
    return (s_ButtonMode);
}


void Button_SetMode( eButtonMode iMode )
{
    s_ButtonMode = iMode;
    s_TimeoutLearnButtonCnt = 0;
}


void Button_RunOne(void)
{
    bool needSwitchState = false;
    U8 i;
    static U8 outputMap;
    static U8 learnCnt;

    switch (s_ButtonMode)
    {
    case NORMAL_BUTTON:
        {
            if( NORMAL == Rf_GetMode() )
            {
                if( (s_SwChange & BUTTON1_ACTIVE) && (s_SwStatus & BUTTON1_ACTIVE) )
                {
                    if ( TIME_TO_LEARN <= s_LearnPrescaleCnt )
                    {
                        Button_SetMode( ENTER_LEARN_BUTTON );
                    }
                    else
                    {
                        Led_InvOutput( (eOutput)s_ButtonMapping[0] );
                    }
                }

                if( (s_SwChange & BUTTON2_ACTIVE) && (s_SwStatus & BUTTON2_ACTIVE) )
                {
                    if ( TIME_TO_LEARN <= s_LearnPrescaleCnt )
                    {
                        Rf_SetMode( ENTER_LEARN_RF );
                    }
                    else
                    {
                        Led_InvOutput( (eOutput)s_ButtonMapping[1] );
                    }
                }

                if( (s_SwChange & BUTTON3_ACTIVE) && (s_SwStatus & BUTTON3_ACTIVE) )
                {
                    Led_InvOutput( (eOutput)s_ButtonMapping[2] );
                }

                if( (s_SwChange & BUTTON4_ACTIVE) && (s_SwStatus & BUTTON4_ACTIVE) )
                {
                    Led_InvOutput( (eOutput)s_ButtonMapping[3] );
                }

                if( (s_SwChange & BUTTON5_ACTIVE) && (s_SwStatus & BUTTON5_ACTIVE) )
                {
                    Led_InvOutput( (eOutput)s_ButtonMapping[4] );
                }

                if ( !(s_SwStatus & BUTTON6_ACTIVE) )
                {
                    s_LearnPrescaleCnt = 0;
                }
            }
        } break;

    case ENTER_LEARN_BUTTON:
        {
            for (i=0; i<TOTAL_BUTTON; ++i) s_ButtonMapping[i] = NO_RELAY;
            outputMap = RELAY1;
            learnCnt = 0;
            Button_SetMode( PREPARE_LEARN_BUTTON_FOR_RELAY );
        } break;

    case PREPARE_LEARN_BUTTON_FOR_RELAY:
        {
            Led_SetAllOutput(false);
            Led_SetOutput( (eOutput)outputMap, true );
            Button_SetMode( LEARN_BUTTON_FOR_RELAY );
        } break;

    case LEARN_BUTTON_FOR_RELAY:
        {
            if( (s_SwChange & BUTTON1_ACTIVE) && (s_SwStatus & BUTTON1_ACTIVE) )
            {
                s_ButtonMapping[0] = outputMap;
                needSwitchState = true;
            }
            else if( (s_SwChange & BUTTON2_ACTIVE) && (s_SwStatus & BUTTON2_ACTIVE) )
            {
                s_ButtonMapping[1] = outputMap;
                needSwitchState = true;
            }
            else if( (s_SwChange & BUTTON3_ACTIVE) && (s_SwStatus & BUTTON3_ACTIVE) )
            {
                s_ButtonMapping[2] = outputMap;
                needSwitchState = true;
            }
            else if( (s_SwChange & BUTTON4_ACTIVE) && (s_SwStatus & BUTTON4_ACTIVE) )
            {
                s_ButtonMapping[3] = outputMap;
                needSwitchState = true;
            }
            else if( (s_SwChange & BUTTON5_ACTIVE) && (s_SwStatus & BUTTON5_ACTIVE) )
            {
                s_ButtonMapping[4] = outputMap;
                needSwitchState = true;
            }

            if ( true == needSwitchState )
            {
                ++outputMap;
                ++learnCnt;
                if ( TOTAL_BUTTON -1 > learnCnt )
                {
                    Button_SetMode( PREPARE_LEARN_BUTTON_FOR_RELAY );
                }
                else
                {
                    Button_SetMode( QUIT_LEARN_BUTTON );
                }
            }

            if( TIMEOUT_LEARN_BUTTON <= s_TimeoutLearnButtonCnt )
            {
                Button_SetMode( QUIT_LEARN_BUTTON );
            }
        } break;

    case QUIT_LEARN_BUTTON:
        {
            Rf_SaveButtonMapping();
            Led_SetAllOutput(false);
            Button_SetMode( NORMAL_BUTTON );
        } break;
    }

    s_SwChange = 0;
}
